use std::collections::HashMap;

use chrono::NaiveDateTime;
use sea_orm::prelude::Expr;
use sea_orm::ActiveValue::NotSet;
use sea_orm::{
    ActiveModelTrait, ColumnTrait, ConnectionTrait, DbConn, DerivePartialModel, EntityTrait,
    FromQueryResult, Iden, IntoActiveModel, PartialModelTrait, QueryFilter, QueryOrder,
    QuerySelect, QueryTrait, Set, TransactionTrait,
};
use serde::{Deserialize, Serialize};
use validator::Validate;

use crate::entity::sys_dept;
type Result<T> = std::result::Result<T, sea_orm::DbErr>;

use crate::entity::sys_dept::Entity as SystemDept;

#[derive(Debug, DerivePartialModel, FromQueryResult)]
#[sea_orm(entity = "SystemDept")]
pub struct PartialUser {
    pub dept_id: i32,
}

pub struct Dept;

// 单位详细的数据展示
#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SystemDept")]
pub struct DeptDetailVo {
    pub dept_id: i32,
    pub parent_id: i32,
    pub dept_name: String,
    pub order_num: i32,
    pub description: String,
    pub status: bool,
    pub created_at: NaiveDateTime,
    pub updated_at: NaiveDateTime,
}

// 单位层级关系的数据展示
#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SystemDept")]
pub struct Dept2Vo {
    pub dept_id: i32,
    pub parent_id: i32,
    pub ancestors: String,
    pub status: bool,
}

// 单位列表的数据展示
#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SystemDept")]
pub struct DeptListVo {
    pub dept_id: i32,
    pub parent_id: i32,
    pub dept_name: String,
    pub order_num: i32,
    pub status: bool,
    pub created_at: NaiveDateTime,
}

impl From<sys_dept::Model> for DeptListVo {
    fn from(value: sys_dept::Model) -> Self {
        Self {
            dept_id: value.dept_id,
            parent_id: value.parent_id,
            dept_name: value.dept_name,
            order_num: value.order_num,
            status: value.status,
            created_at: value.created_at,
        }
    }
}

// 单位树形结构的数据
#[derive(Debug, Serialize)]
pub struct DeptTreeVo {
    #[serde(flatten)]
    pub dept: DeptListVo,
    pub children: Option<Vec<DeptTreeVo>>,
}

/// 单位提交的数据
#[derive(Debug, FromQueryResult, Deserialize, Validate)]
pub struct DeptDo {
    pub parent_id: Option<i32>,
    #[validate(length(min = 3, max = 32), non_control_character)]
    pub dept_name: String,
    pub phone: Option<String>,
    pub email: Option<String>,
    pub description: Option<String>,
    #[serde(default)]
    pub order_num: Option<i32>,
    pub status: Option<bool>,
}

impl Dept {
    ane_macros::model_fetch!(
        #model=sys_dept
        /// 根据id查找部门
        pub fn get_by_id(DeptId.eq(dept_id: i32), Status.eq(status: Option<bool>), DelFlag.eq(del: Option<bool>))
    );

    ane_macros::model_fetch!(
        #model=sys_dept
        #order=[OrderNum:Asc]
        #exec=all
        /// 根据id查找部门
        pub fn get_child_dept_list(ParentId.eq(dept_id: i32), Status.eq(status: Option<bool>), DelFlag.eq(del: Option<bool>))
    );

    pub async fn create(db: &DbConn, data: DeptDo) -> Result<Option<sys_dept::Model>> {
        let p_id = if let Some(p) = data.parent_id {
            p
        } else {
            return Ok(None);
        };
        let ancestors = if p_id == 0 {
            "/0/".to_string()
        } else {
            if let Some(ancestors) = sys_dept::Entity::find_by_id(p_id)
                .select_only()
                .column(sys_dept::Column::Ancestors)
                .filter(sys_dept::Column::DelFlag.eq(false))
                .into_tuple::<String>()
                .one(db)
                .await?
            {
                ancestors
            } else {
                return Ok(None);
            }
        };
        let active = sys_dept::ActiveModel {
            parent_id: Set(p_id),
            ancestors: Set("".to_owned()),
            dept_name: Set(data.dept_name),
            phone: Set(data.phone.unwrap_or_default()),
            email: Set(data.email.unwrap_or_default()),
            description: Set(data.description.unwrap_or_default()),
            order_num: Set(data.order_num.unwrap_or_default()),
            status: Set(data.status.unwrap_or_default()),
            del_flag: Set(false),
            dept_id: NotSet,
            manager: Set("".to_owned()),
            ..Default::default()
        };
        let txn = db.begin().await?;
        let model = active.insert(&txn).await?;
        let ancestors = format!("{}{}/", ancestors, model.dept_id);
        let mut a_model = model.into_active_model();
        a_model.set(sys_dept::Column::Ancestors, ancestors.into());
        let model = a_model.update(&txn).await?;
        txn.commit().await?;
        Ok(Some(model))
    }

    pub async fn update(db: &DbConn, id: i32, data: DeptDo) -> Result<Option<sys_dept::Model>> {
        use sys_dept::{ActiveModel, Column, Entity};

        // 检查parent_id是否存在是否成环
        let p_ancestors = if let Some(p_id) = data.parent_id {
            let p_ancestors = if p_id == 0 {
                "/0/".to_string()
            } else {
                if let Some(p_ancestors) = Entity::find_by_id(p_id)
                    .select_only()
                    .column(Column::Ancestors)
                    .filter(Column::DelFlag.eq(false))
                    .into_tuple::<String>()
                    .one(db)
                    .await?
                    .filter(|a| a.find(&format!("/{id}/")).is_none())
                {
                    p_ancestors
                } else {
                    return Ok(None);
                }
            };
            Some(p_ancestors)
        } else {
            None
        };

        let txn = db.begin().await?;
        let model = ActiveModel {
            dept_id: Set(id),
            dept_name: Set(data.dept_name),
            parent_id: data.parent_id.map(Set).unwrap_or(Default::default()),
            phone: data.phone.map(Set).unwrap_or(Default::default()),
            email: data.email.map(Set).unwrap_or(Default::default()),
            description: data.description.map(Set).unwrap_or(Default::default()),
            order_num: data.order_num.map(Set).unwrap_or(Default::default()),
            status: data.status.map(Set).unwrap_or(Default::default()),
            ..Default::default()
        }
        .update(&txn)
        .await?;
        if let Some(p_ancestors) = p_ancestors {
            if !model
                .ancestors
                .ends_with(&format!("/{}/{}/", model.parent_id, model.dept_id))
            {
                let expr = format!(
                    "CONCAT(\"{}{}/\",SUBSTRING(`{}`,{}))",
                    p_ancestors,
                    model.dept_id,
                    Column::Ancestors.to_string(),
                    model.ancestors.len() + 1
                );
                Entity::update_many()
                    .filter(Column::Ancestors.starts_with(&model.ancestors))
                    .col_expr(Column::Ancestors, Expr::cust(expr))
                    .exec(&txn)
                    .await?;
            }
        }
        txn.commit().await?;
        Ok(Some(model))
    }

    /// 软删除一个单位, 单位不存在抛出错误 [DbErr::RecordNotUpdated](sea_orm::DbErr::RecordNotUpdated)
    pub async fn soft_delete(db: &DbConn, id: i32) -> Result<sys_dept::Model> {
        let model = sys_dept::ActiveModel {
            dept_id: Set(id),
            del_flag: Set(true),
            ..Default::default()
        };
        sys_dept::Entity::update(model).exec(db).await
    }

    /// 删除一个单位
    pub async fn delete(db: &DbConn, id: i32) -> Result<u64> {
        sys_dept::Entity::delete_by_id(id)
            .exec(db)
            .await
            .map(|r| r.rows_affected)
    }

    /// 获得一个部门的树结构
    /// - id 1 为全部树
    /// - status 状态 true正常 false停用
    pub async fn get_tree(
        db: &DbConn,
        id: i32,
        status: Option<bool>,
    ) -> Result<Option<DeptTreeVo>> {
        let root = if let Some(root) = sys_dept::Entity::find_by_id(id).one(db).await? {
            root
        } else {
            return Ok(None);
        };
        let sql = sys_dept::Entity::find()
            .filter(sys_dept::Column::Ancestors.starts_with(&root.ancestors))
            .filter(sys_dept::Column::DelFlag.eq(false))
            .apply_if(status, |sql, v| sql.filter(sys_dept::Column::Status.eq(v)))
            .order_by_asc(sys_dept::Column::OrderNum);

        let childs = sql.into_partial_model::<DeptListVo>().all(db).await?;
        let mut childs_map: HashMap<i32, Vec<DeptListVo>> = HashMap::new();
        for ele in childs {
            if let Some(d) = childs_map.get_mut(&ele.parent_id) {
                d.push(ele);
            } else {
                childs_map.insert(ele.parent_id, vec![ele]);
            }
        }
        let childs = recursion_tree(childs_map, &id).1;
        let data = DeptTreeVo {
            dept: root.into(),
            children: childs,
        };
        Ok(Some(data))
    }

    /// 检查`child_id单位`是否是`id单位`的子单位
    pub async fn check_is_child(db: &DbConn, id: i32, child_id: i32) -> Result<bool> {
        sys_dept::Entity::find_by_id(child_id)
            .select_only()
            .column(sys_dept::Column::Ancestors)
            .into_tuple::<String>()
            .one(db)
            .await
            .map(|a| a.is_some_and(|a| a.contains(&format!("/{id}/"))))
    }
}

fn recursion_tree(
    mut data: HashMap<i32, Vec<DeptListVo>>,
    id: &i32,
) -> (HashMap<i32, Vec<DeptListVo>>, Option<Vec<DeptTreeVo>>) {
    if let Some(childs) = data.remove(&id) {
        let mut tmp = Vec::new();
        for c in childs {
            let d = recursion_tree(data, &c.dept_id);
            data = d.0;
            tmp.push(DeptTreeVo {
                dept: c,
                children: d.1,
            });
        }
        (data, Some(tmp))
    } else {
        (data, None)
    }
}
